﻿using System;
using System.Collections.Generic;
using System.IO;
using Unity.Mathematics;
using UnityEngine;
using WorldMapBase.Tile;
using WorldMapBase.Tile.Pool;
using WorldMapNew;
using XLua;
using Yoozoo.Core.Common;
using Yoozoo.Managers.ResourceManagerV2.Framework.Resource;
using Yoozoo.Managers.ResourceManagerV2.Runtime;

namespace WorldMapBase
{
    /// <summary>
    /// 地图数据
    /// </summary>
    public class WorldMapConfigData
    {
        // ========================================================================= 地图数据 =========================================================================
        private static ResLoader m_resLoader;
        private static ResLoader m_resLoader_initChunck;// 初始化地图块加载
        private static ResLoader m_resLoader_chunck;// 其他地图块加载


        private static Dictionary<int, MapPointInfo> m_mapPointPos;

        private static Dictionary<int, ResourceData> m_resourceDataMap; // <resId,ResourceData> C#端资源映射
        public static Dictionary<int, ResourceData> ResourceDatas => m_resourceDataMap;

        private static WorldMapData m_mapData;                                                                              // 原始地图数据
        public static int m_mapWorldDataMaxIdx = 10000;                                                                     // 地图数据最大尺寸 不算粒度在30x30大小 1200x1200坐标系下 idx最大为40x40 - 1
        private static Dictionary<int, int> m_mapLodDataSize = new Dictionary<int, int>(0);                                 // <lod,DataSize> 例：lod1 地图数据尺寸 30 lod2 地图块尺寸 90
        private static Dictionary<int, Dictionary<int, int>> m_mapRunDatas = new Dictionary<int, Dictionary<int, int>>(0);  // <layerId,<lod,tileSize>>
        public static Dictionary<int, string> MapPrefabMapRunTime = new Dictionary<int, string>(0);                         // 资源id - 资源路径

        public static bool bMapChunckDateInit = false;
        [BlackList]
        private static Dictionary<int, MapChunckData> MapChunckDataRunTime = new Dictionary<int, MapChunckData>(0);     // 地图块数据缓存
        private static List<Vector2> MapInitPoints = new List<Vector2>();                                               // 沙盘初始化需要预加载的地图位置
        private static Dictionary<int,bool> MapInitChunckIds = new Dictionary<int, bool>();                             // 沙盘初始化需要预加载的地图块配置id <加载的地图块id,加载完成状态>
        private static int MapInitChunckNum = 0;                                                                        // 沙盘初始化需要预加载的地图块配置id 数量
        private static Dictionary<int, bool> MapChunckDataLoad = new Dictionary<int, bool>();                           // 地图块数据加载记录
        private static LuaFunction MapDataLoadEndCallBack;                                                              // 沙盘初始化加载结束回调

        private static Dictionary<int, int> MapHideMapPoints;
        private static Dictionary<int, Dictionary<int,int>> MapHideMapItems;
        private static Dictionary<int, bool> MapDeleteAlliancePoint;

        // ========================================================================= 迷雾 =========================================================================
        private static WorldMapFogData m_mapFogData;                                                                    // 原始地图迷雾数据 舍弃
        private static Dictionary<int, List<Vector2Int>> m_mapFogTiles;                                                 // 迷雾占地数据 -用于设置采样图 舍弃
        private static Dictionary<int, int> m_mapFogIdxToId;                                                            // 迷雾一维下标映射迷雾id -用于点击活动对应迷雾所属id 舍弃

        // ========================================================================= 装饰物 =========================================================================
        public static int _allianceChunckPointLineNum = 3;                                                              // 一个30x30 一行街区点数量 默认3个
        public static int _alliancePointSize = 10;                                                                      // 一个街区点所占尺寸 写死10
        public static int _allianceTileLineNum = WorldEntry.m_mapSize / WorldEntry.m_iTileSize;                         // 大地图一行地图块数量
        public static int _allianceMapPointLineNum = WorldEntry.m_mapSize / _alliancePointSize;                         // 大地图一行街区点数据
        public static int _allainceTildHalfSize = 15;                                                                   // 地图块尺寸0.5

        public static Dictionary<int, Dictionary<int, Vector3>> MapPointPosRunTime = new Dictionary<int, Dictionary<int, Vector3>>();// 地图出生点坐标映射 <chunckId(经过旋转),cfgIdx(经过旋转),localPos(经过旋转)>

        // ========================================================================= 海外地图 =========================================================================
        private static Dictionary<int, Dictionary<int, OverSeaChunck>> overSeaChunckIdMap; // 海外地图块id映射 <lod,<tileIdx,OverSeaChunck>> 
        private static Dictionary<string, List<Vector2>> overSeaShapes = new Dictionary<string, List<Vector2>>();// 海外地图块形状 -用于海外点击的模糊判断

        // 加载预制体映射文件
        public static void LoadMapPrefabMap(LuaFunction callBack)
        {
            
            LoadingUtils.RecodeTimeStart("LoadMapPrefabMap");
            string mapPrefabMapPath = "Assets/ResourcesAssets/World/mapdata/mapPrefabMap.asset";
            if (m_resLoader == null)
            {
                m_resLoader = ResLoader.Alloc();
            }
            m_resLoader.Add2Load(mapPrefabMapPath, (bool success, string assetName, object asset) =>
            {
                if (success)
                {
                    UpdateMaPrefabMap(asset);
                    Debug.Log("[沙盘加载] =================== LoadMapPrefabMap 完成 =================== Count : " + m_resourceDataMap.Keys.Count);
                }
                if (callBack != null)
                {
                    callBack.Call();
                }
                LoadingUtils.RecodeTimeEnd("LoadMapPrefabMap");
            });
            m_resLoader.Load();
        }

        public static void LoadMapPointData()
        {
            LoadingUtils.RecodeTimeStart("LoadMapPointData");
            string path = "Assets/ResourcesAssets/World/mapdata/client_pointData.asset";
            if (m_resLoader == null)
            {
                m_resLoader = ResLoader.Alloc();
            }
            m_resLoader.Add2Load(path, (bool success, string assetName, object asset) =>
            {
                if (success)
                {
                    WorldMapPointData pointData = asset as WorldMapPointData;
                    if (pointData)
                    {
                        m_mapPointPos = new Dictionary<int, MapPointInfo>(pointData.mapPointDatas.Count);
                        for (int i = 0; i < pointData.mapPointDatas.Count; i++)
                        {
                            MapPointInfo data = pointData.mapPointDatas[i];
                            m_mapPointPos[data.idx] = data;
                        }
                    }
                    Debug.Log("[沙盘加载] =================== LoadMapPointData 完成 =================== ");
                    LoadingUtils.RecodeTimeEnd("LoadMapPointData");
                }
            });
            m_resLoader.Load();
        }

        public static void UpdateMaPrefabMap(object asset)
        {
            LoadingUtils.RecodeTimeStart("UpdateMaPrefabMap");
            m_resourceDataMap = new Dictionary<int, ResourceData>(0);
            MapPrefabMap prefabMap = asset as MapPrefabMap;
            if (prefabMap)
            {
                m_resourceDataMap = new Dictionary<int, ResourceData>(prefabMap.mapPrefabMap.Count);
                MapPrefabMapRunTime = new Dictionary<int, string>(prefabMap.mapPrefabMap.Count);
                for (int i = 0; i < prefabMap.mapPrefabMap.Count; i++)
                {
                    PrefabData data = prefabMap.mapPrefabMap[i];
                    string path = data.resPath;
                    // var hasAssetResult = UMTResource.HasAsset(path); // 检查一下data存在
                    // if (hasAssetResult != HasAssetResult.NotExist)
                    // {
                    //   
                    // }
                    // else
                    // {
                    //     Debug.LogError("[UpdateMaPrefabMap] 文件不存在 => " + path);
                    // }
                    int id = data.resID;
                    MapPrefabMapRunTime[id] = path;
                    if (path.Contains("prefab"))// 是预制体才添加到资源
                    {
                        int poolNum = data.poolNum;
                        ResourceData resData = new ResourceData(id, path, poolNum);
                        m_resourceDataMap[id] = resData;
                    }
                }
            }
            LoadingUtils.RecodeTimeEnd("UpdateMaPrefabMap");
        }

        // 获得资源路径
        public static string GetMapPrefabPath(int resId)
        {
            string path = "";
            if (MapPrefabMapRunTime.ContainsKey(resId)) path = MapPrefabMapRunTime[resId];
            return path;
        }

        public static void SetWorldInitPoints(Vector2 pos,bool bClear = false)
        {
            if (bClear)
            { 
                MapInitPoints.Clear();
            }
            MapInitPoints.Add(pos);
        }

        // 统计需要初始化加载的地图块id
        private static void SumWorldInitChunckIds()
        {
            MapInitChunckIds.Clear();
            MapInitChunckNum = 0;
            int lodIndex = 1;
            for (int i = 0; i < MapInitPoints.Count; i++)
            {
                Vector2 point = MapInitPoints[i];
                int tileIdx = GetMapIdxByPos(point, lodIndex,out int lineNum);
                int idx_x = (int)(point.x % lineNum);
                int idx_y = (int)(point.y / lineNum);
                // 添加九格以内的地图块
                for (int x = -1; x <= 1; x++)
                {
                    for (int y = -1; y <= 1; y++)
                    {
                        int tile_x = idx_x + x;
                        int tile_y = idx_y + y;
                        if (tile_x >= 0 && tile_x < lineNum && tile_y >= 0 && tile_y < lineNum)// 判断地图数据的边界情况
                        {
                            int tileIdx1 = tile_x + tile_y * lineNum;
                            int resId = GetTileResId(lodIndex, tileIdx1, out int tileSize);
                            if (!MapInitChunckIds.ContainsKey(resId))
                            {
                                MapInitChunckIds[resId] = false;
                                MapInitChunckNum++;
                            }
                        }
                    }
                }
            }
            Debug.Log("[沙盘加载] =================== SumWorldInitChunckIds =================== Num ：" + MapInitChunckNum);
            MapInitPoints.Clear();
        }

        private static void CheckLoadInitChunckIdEnd(int chunckId)
        {
            Debug.Log("[沙盘加载] =================== CheckLoadInitChunckIdEnd =================== chunckId : " + chunckId);
            if (MapInitChunckIds.ContainsKey(chunckId))
            {
                Debug.Log("[沙盘加载] =================== CheckLoadInitChunckIdEnd is Init =================== chunckId : " + chunckId);
                bool state = MapInitChunckIds[chunckId];
                if (!state)
                {
                    MapInitChunckIds[chunckId] = true;
                    MapInitChunckNum--;
                    if (MapInitChunckNum <= 0)
                    {
                        Debug.Log("[沙盘加载] =================== CheckLoadInitChunckIdEnd End =================== ");
                        LuaFunction func = MapDataLoadEndCallBack;
                        if (func != null) func.Action(true);
                        MapDataLoadEndCallBack = null;
                    }
                }
            }
        }

        public static void LoadMapData(LuaFunction luaFunc)
        {
           
            MapDataLoadEndCallBack = luaFunc;
            if (m_resLoader == null) m_resLoader = ResLoader.Alloc();
            string mapPrefabMapPath = "Assets/ResourcesAssets/World/mapdata/MapRoot_mapdata.asset";
            if (m_resLoader == null)
            {
                m_resLoader = ResLoader.Alloc();
            }
            m_resLoader.Add2Load(mapPrefabMapPath, (bool success, string assetName, object asset) =>
            {
                LoadingUtils.RecodeTimeStart("LoadMapData");
                if (success)
                {
                    Debug.Log("[沙盘加载] =================== UpdateMapData 开始 =================== ");
                    UpdateMapData(asset);
                }
                
                LoadingUtils.RecodeTimeEnd("LoadMapData");
            });
            m_resLoader.Load();
            
        }

        // 更新地图数据
        public static void UpdateMapData(object asset)
        {
            MapChunckDataLoad.Clear();
            // 直接使用加载数据
            m_mapData = asset as WorldMapData;
            m_mapRunDatas = new Dictionary<int, Dictionary<int, int>>(m_mapData.mapLayerRunDtas.Count);
            // 解析大地图粒度 层级-lod-tileSize
            for (int i = 0; i < m_mapData.mapLayerRunDtas.Count; i++)
            {
                var layerRunData = m_mapData.mapLayerRunDtas[i];
                Dictionary<int, int> layerRunLod = new Dictionary<int, int>(layerRunData.displayLods.Count);
                for (int ii = 0; ii < layerRunData.displayLods.Count; ii++)
                {
                    int2 lod_size = layerRunData.displayLods[ii];
                    layerRunLod[lod_size.x] = lod_size.y;// x - lod y - tileSize
                }
                m_mapRunDatas[layerRunData.layerID] = layerRunLod;
            }

            m_mapLodDataSize = new Dictionary<int, int>(m_mapData.mapLODDatas.Count);
            for (int i = 0; i < m_mapData.mapLODDatas.Count; i++)
            {
                var lodData = m_mapData.mapLODDatas[i];
                m_mapLodDataSize[(int)lodData.lodDistance] = lodData.tileSize;// 记录数据尺寸
            }
            bMapChunckDateInit = true;
            // 预加载初始的地图块数据
            SumWorldInitChunckIds();
            if (MapInitChunckNum <= 0)
            {
                Debug.Log("[沙盘加载] =================== UpdateMapData 没有预加载地图块 =================== ");
                LuaFunction func = MapDataLoadEndCallBack;
                if (func != null) func.Action(true);
                MapDataLoadEndCallBack = null;
            }
            else
            {
                m_resLoader_initChunck = ResLoader.Alloc();
                foreach (int id in MapInitChunckIds.Keys)
                {
                    LoadMapChunckData(id, m_resLoader_initChunck);
                }
                m_resLoader_initChunck.Load();
            }

            // 加载所有的地图块数据
            m_resLoader_chunck = ResLoader.Alloc();
            for (int i = 0; i < m_mapData.mapChunckResIds.Count; i++)
            {
                int resId = m_mapData.mapChunckResIds[i];
                LoadMapChunckData(resId, m_resLoader_chunck);
            }
            m_resLoader_chunck.Load();
            // 解析出生点删除数据
            if (MapHideMapPoints == null)
            {
                MapHideMapPoints = new Dictionary<int, int>(m_mapData.mapChunckDeleatePoints.Count);
            }
            MapHideMapPoints.Clear();
            for (int i = 0;i < m_mapData.mapChunckDeleatePoints.Count;i++)
            {
                int pointId = m_mapData.mapChunckDeleatePoints[i];
                MapHideMapPoints[pointId] = pointId;
            }
            // 解析装饰物删除数据
                    //private static Dictionary<int, Dictionary<int, int>> MapHideMapItems;
            if (MapHideMapItems == null)
            {
                MapHideMapItems = new Dictionary<int, Dictionary<int, int>>(m_mapData.mapChunckDeleateDatas.Count);
            }
            MapHideMapItems.Clear();
            for (int i = 0; i < m_mapData.mapChunckDeleateDatas.Count; i++)
            {
                List<int> deleateIdxs = m_mapData.mapChunckDeleateDatas[i].deleateIdx;
                if (deleateIdxs.Count > 0)
                {
                    Dictionary<int, int> mapIdx = new Dictionary<int, int>(deleateIdxs.Count);
                    for (int ii = 0; ii < deleateIdxs.Count; ii++)
                    {
                        int deleateItemIdx = deleateIdxs[ii];
                        mapIdx[deleateItemIdx] = deleateItemIdx;
                    }
                    MapHideMapItems[i] = mapIdx;
                }
            }

            // 解析空白街区点数据
            if (MapDeleteAlliancePoint == null) MapDeleteAlliancePoint = new Dictionary<int, bool>(m_mapData.mapAllianceDeleatePoints.Count);
            for (int i = 0; i < m_mapData.mapAllianceDeleatePoints.Count; i++)
            {
                MapDeleteAlliancePoint[m_mapData.mapAllianceDeleatePoints[i]] = true;
            }
            // 解析边界地块数据
            overSeaChunckIdMap = new Dictionary<int, Dictionary<int, OverSeaChunck>>();
            for (int i = 0; i < m_mapData.mapLODDatas.Count; i++)
            {
                var lodData = m_mapData.mapLODDatas[i];
                Dictionary<int, OverSeaChunck> chunckIdMap = new Dictionary<int, OverSeaChunck>();
                for (int ii = 0; ii < lodData.mapOverSeaChuncks.Count; ii++)
                {
                    OverSeaChunck chunck = lodData.mapOverSeaChuncks[ii];
                    int tileIdx = GetOverSeaTileIdx(chunck.offset_x, chunck.offset_y, WorldEntry.m_iTileSize); 
                    chunckIdMap[tileIdx] = chunck;
                }
                overSeaChunckIdMap[(int)lodData.lodDistance] = chunckIdMap;
            }
            // 解析海外副本边界
            for (int i = 0; i < m_mapData.mapOverSeaShapeInfos.Count; i++)
            {
                OverSeaShapeInfo info = m_mapData.mapOverSeaShapeInfos[i];
                overSeaShapes[info.key] = info.points;
            }

        }

        // 加载一个地图块数据
        public static void LoadMapChunckData(int chunckId,ResLoader resload)
        {
            chunckInfoDta chunckInfo = GetChunckInfoById(chunckId);
            chunckInfo.rotation = 0;
            int chunckId_0 = GetChunckIdByInfo(chunckInfo);
            if (!MapPrefabMapRunTime.ContainsKey(chunckId_0))
            {
                UnityEngine.Debug.LogWarningFormat("未找到chunkId={0} chunckId_0{1} 所对应的路径", chunckId, chunckId_0);
                // 检查初始地图块加载完成 - 就算资源没有也让登录不卡死
                CheckLoadInitChunckIdEnd(chunckId);
                return;
            }
            if (!MapChunckDataLoad.ContainsKey(chunckId))// 检查是否添加到加载队列
            {
                MapChunckDataLoad[chunckId] = true;
                string path = MapPrefabMapRunTime[chunckId_0];
                // 加载该id的地图数据
                resload.Add2Load(path, typeof(MapChunckData),(bool success, string assetName, object asset) =>
                {
                    if (success)
                    {
                        MapChunckData data = asset as MapChunckData;
                        MapChunckDataRunTime[chunckId_0] = data;
                        InitChunckData(chunckId, data.alliancePointRoads, data.alliancePointCross);
                        InitChunckAdornData(chunckId, data);
                    }
                    else
                    {
                        // 地图块加载失败
                    }
                    // 检查初始地图块加载完成
                    CheckLoadInitChunckIdEnd(chunckId);
                });
            }
        }

        public static WorldMapData GetMapData()
        {
            return m_mapData;
        }

        /// <summary>
        /// 获取地图块数据
        /// </summary>
        public static WorldMapNew.MapChunckLayer GetTileData(int layer, int lodIndex, int tileIndex,out int tileSize, out int layerIdx,out int chunckResId)
        {
            // 注意 这里传入的tileIndex可能是海外坐标系
            tileSize = WorldEntry.m_iTileSize;
            layerIdx = tileIndex;
            // 将粒度tileIndex转换成该层级的idx
            //layerIdx = GetTileDataIdx(layer,lodIndex,tileIndex); 暂时先注释 后续如果要使用粒度再打开
            if (tileIndex >= m_mapWorldDataMaxIdx) // 
            {
                chunckResId = GetOverSeaTileResId(lodIndex, layerIdx, out tileSize);
            }
            else
            {
                chunckResId = GetTileResId(lodIndex, layerIdx, out tileSize);
            }
            int chunckResId_0 = GetTileResId_0(chunckResId);
            if (chunckResId_0 > 0 && MapChunckDataRunTime.ContainsKey(chunckResId_0))
            {
                var mapChunckData = MapChunckDataRunTime[chunckResId_0];
                if (mapChunckData == null)
                {
                    return null;
                }
                for (int i = 0; i < mapChunckData.mapLayers.Count; i++)
                {
                    var layerData = mapChunckData.mapLayers[i];
                    if (layerData.layerID == layer)
                    {
                        return layerData;
                    }
                }
            }
            else
            {
                Debug.LogError(string.Format("GetTileData - not find data layer:{0} lodIndex:{1} tileIndex:{2}", layer,lodIndex,tileIndex));
            }
            return null;
        }

        public static MapChunckData GetMapChunckData(int id)
        {
            MapChunckData data = null;
            if (MapChunckDataRunTime.ContainsKey(id))
            {
                data = MapChunckDataRunTime[id];
            }
            return data;
        }

        public static bool GetMapPointHide(int pointId)
        {
            bool hide = false;
            if (MapHideMapPoints != null && MapHideMapPoints.ContainsKey(pointId))
            {
                hide = true;
            }
            return hide;
        }

        public static bool GetElementShow(int chuncIdx,int itemIdx)
        {
            bool hide = false;
            if (MapHideMapItems != null && MapHideMapItems.ContainsKey(chuncIdx))
            {
                Dictionary<int, int> mapIdx = MapHideMapItems[chuncIdx];
                if (mapIdx != null && mapIdx.ContainsKey(itemIdx))
                {
                    hide = true;
                }
            }
            return hide;
        }

        public static int GetTileDataIdx(int layer, int lodIndex, int tileIndex)
        {
            int idx = tileIndex;
            if (m_mapData != null)
            {
                m_mapLodDataSize.TryGetValue(lodIndex, out int tileSize);
                if (m_mapRunDatas.TryGetValue(layer, out Dictionary<int, int> lod_size))
                {
                    if (lod_size.TryGetValue(lodIndex, out int dataSize))// 查找到对应粒度
                    {
                        if (tileSize > dataSize)// 粒度和地图尺寸不一样
                        {
                            // tileIndex 是 粒度坐标系下 一维坐标
                            int layerRol = m_mapData.mapWidth / dataSize;
                            int granuleNum = tileSize / dataSize;
                            int tile_x = tileIndex % layerRol;
                            int tile_y = tileIndex / layerRol;
                            int idx_x = (int)math.ceil(tile_x / granuleNum);
                            int idx_y = (int)math.ceil(tile_y / granuleNum);
                            int tileRol = m_mapData.mapWidth / tileSize;
                            idx = idx_x + idx_y * tileRol;
                        }
                    }
                }
            }
            return idx;
        }

        public static int GetTileSize(int layer, int lodIndex)
        {
            int tileSize = WorldEntry.m_iTileSize;
            if (m_mapData != null)
            {
                if (m_mapRunDatas.TryGetValue(layer, out Dictionary<int, int> lod_size))
                {
                    if (lod_size.TryGetValue(lodIndex, out int dataSize))// 查找到对应粒度
                    {
                        tileSize = dataSize;
                    }
                }
            }
            return tileSize;
        }

        public static int GetChunckId(int tileIdx, out int rotation)
        {
            int chunckId1 = GetTileResId(1, tileIdx, out int tileSize); // 此时的chunckId可能是旋转过的
            chunckInfoDta data = GetChunckInfoById(chunckId1);
            rotation = data.rotation;
            data.rotation = 0;
            int chunckId = GetChunckIdByInfo(data);
            return chunckId;
        }

        /// <summary>
        /// 获取地块资源id
        /// </summary>
        public static int GetTileResId(int lodIndex, int tileIndex, out int tileSize)
        {
            int resId = 0;
            tileSize = WorldEntry.m_iTileSize;
            if (bMapChunckDateInit == false)
            {
                return resId;
            }
            for (int i = 0; i < m_mapData.mapLODDatas.Count; i++)
            {
                var lodData = m_mapData.mapLODDatas[i];
                if (lodData.lodDistance == lodIndex)
                {
                    tileSize = lodData.tileSize;
                    if (lodData.mapChunckIds != null && lodData.mapChunckIds.Count > tileIndex)
                    {
                        resId = lodData.mapChunckIds[tileIndex];
                    }
                }
            }

            return resId;
        }

        /// <summary>
        /// 获取地块资源id
        /// </summary>
        public static int GetOverSeaTileResId(int lodIndex, int tileIndex, out int tileSize)
        {
            int resId = 0;
            tileSize = WorldEntry.m_iTileSize;
            if (bMapChunckDateInit == false)
            {
                return resId;
            }
            for (int i = 0; i < m_mapData.mapLODDatas.Count; i++)
            {
                var lodData = m_mapData.mapLODDatas[i];
                if (lodData.lodDistance == lodIndex)
                {
                    tileSize = lodData.tileSize;
                    if (overSeaChunckIdMap.TryGetValue(lodIndex, out Dictionary<int, OverSeaChunck> overSeaChunckMap))
                    {
                        if (overSeaChunckMap.TryGetValue(tileIndex, out OverSeaChunck chunckInfo))
                        {
                            return chunckInfo.chunckId;
                        }
                    }
                }
            }

            return resId;
        }

        public static int GetTileResId_0(int resId)
        {
            int chunckResId = resId;
            chunckInfoDta data = GetChunckInfoById(resId);
            data.rotation = 0;
            chunckResId = GetChunckIdByInfo(data);
            return chunckResId;
        }

        public static Vector2Int GetTileGridByIndex(int layer, int lodIndex, int tileIndex)
        {
            Vector2Int res = new Vector2Int(-1, -1);
            if (bMapChunckDateInit == false)
            {
                return res;
            }
            // 获取该layer lod 下tileSize
            if (m_mapRunDatas.ContainsKey(layer))
            {
                var dicLodTileSize = m_mapRunDatas[layer];
                if (dicLodTileSize.ContainsKey(lodIndex))
                {
                    int tileSize = dicLodTileSize[lodIndex];
                    int tileNum = m_mapData.mapWidth / tileSize;
                    if (tileIndex > m_mapWorldDataMaxIdx)
                    {
                        int2 worldPos = GetOverSeaWorldPosByIdx(tileIndex, tileSize);
                        return new Vector2Int(worldPos.x, worldPos.y);
                    }
                    else
                    {
                        int gridX = tileIndex % tileNum;
                        int gridY = tileIndex / tileNum;
                        return new Vector2Int(gridX, gridY);
                    }
                 
                }
            }
            return res;
        }

        public static void Dispose()
        {
            if (m_resLoader != null)
            {
                m_resLoader.Recycle2Cache();
                m_resLoader = null;
            }
            if (m_resLoader_initChunck != null)
            {
                m_resLoader_initChunck.Recycle2Cache();
                m_resLoader_initChunck = null;
            }
            if (m_resLoader_chunck != null)
            {
                m_resLoader_chunck.Recycle2Cache();
                m_resLoader_chunck = null;
            }
            m_resourceDataMap = null;
            m_mapData = null;
            m_mapLodDataSize.Clear();
            m_mapRunDatas.Clear();
            MapPrefabMapRunTime.Clear();
            bMapChunckDateInit = false;
            MapChunckDataRunTime.Clear();
            MapInitPoints.Clear();
            MapInitChunckIds.Clear();
            MapInitChunckNum = 0;
            MapChunckDataLoad.Clear();
            MapDataLoadEndCallBack = null;
        }

        // 获得地图块数据在大地图的位置
        public static Vector3 GetMapChunckPos(int layer,int lodIndex, int idx)
        {
            Vector3 pos = Vector3.zero;
            if (bMapChunckDateInit == false)
            {
                return pos;
            }
            // 获取该layer lod 下tileSize
            int tileSize = -1;
            if (m_mapLodDataSize.ContainsKey(lodIndex))
            {
                tileSize = m_mapLodDataSize[lodIndex];
            }
            if (tileSize > 0)
            {
                if (idx >= m_mapWorldDataMaxIdx)
                {
                    int2 worldPos = GetOverSeaWorldPosByIdx(idx, tileSize);
                    pos.x = (worldPos.x + 0.5f) * tileSize;
                    pos.z = (worldPos.y + 0.5f) * tileSize;
                }
                else
                {
                    // 计算一维坐标idx 在tileSize粒度下大地图的中心位置 左下角0
                    int lineNum = m_mapData.mapWidth / tileSize;
                    int idx_x = idx % lineNum;
                    int idx_y = idx / lineNum;
                    pos.x = (idx_x + 0.5f) * tileSize;
                    pos.z = (idx_y + 0.5f) * tileSize;
                }
               
            }
            return pos;
        }

        public static int GetMapIdxByPos(Vector2 pos, int lodIndex,out int lineNum)
        {
            lineNum = 0;
            int tileIdx = -1;
            // 获取该layer lod 下tileSize
            int tileSize = -1;
            if (m_mapLodDataSize.ContainsKey(lodIndex))
            {
                tileSize = m_mapLodDataSize[lodIndex];
            }
            if (tileSize > 0)
            {
                // 计算一维坐标idx 在tileSize粒度下大地图的中心位置 左下角0
                int lineNum0 = m_mapData.mapWidth / tileSize;
                lineNum = lineNum0;
                int idx_x = (int)(pos.x % lineNum);
                int idx_y = (int)(pos.y / lineNum);

                tileIdx = idx_x + idx_y * lineNum;
            }
            return tileIdx;
        }

        // 获得粒度下标
        public static int GetMapChunckDataIdx(int lodIndex, int tileSize, int tileIdx, int rotation)
        {
            int dataIdx = 0;
            int chunckSize = tileSize;
            m_mapLodDataSize.TryGetValue(lodIndex, out chunckSize);
            if (chunckSize > tileSize)
            {
                int lineNum = m_mapData.mapWidth / tileSize;
                int granuleNum = chunckSize / tileSize;
                int idx_x = tileIdx % lineNum;
                int idx_y = tileIdx / lineNum;
                idx_x = idx_x % granuleNum;
                idx_y = idx_y % granuleNum;
                if (rotation > 0)
                {
                    // 地图块是旋转的 对应粒度所在idx也是需要旋转的
                    dataIdx = GetMapChunckDataIdxByRotation(idx_x, idx_y, granuleNum, rotation);
                }
                else
                { 
                    dataIdx = idx_x + idx_y * granuleNum;
                }
            }
            return dataIdx;
        }

        public static int GetMapChunckDataIdxByRotation(int idx_x, int idx_y, int granuleNum, int rotation)
        {
            int dataIdx = 0;
            int center = (int)Mathf.Floor(granuleNum * 0.5f);
            float x = idx_x - center;
            float y = idx_y - center;
            // 根据rotation旋转
            Vector3 pos = GetPosByAngle(x, 0, y, rotation);
            x = center + pos.x;
            y = center + pos.z;
            dataIdx = (int)(x + y * granuleNum);
            return dataIdx;
        }

        // 按照顺时针 旋转坐标
        public static Vector3 GetPosByAngle(float x, float y, float z, int r)
        {
            Vector3 pos = new Vector3(x, y, z);
            if (r == 1)// 90
            {
                pos.x = z;
                pos.z = -x;
            }
            else if(r == 2)// 180
            {
                pos.x = -x;
                pos.z = -z;
            }
            else if (r == 3)// 270
            {
                pos.x = -z;
                pos.z = x;
            }
            return pos;
        }

        // 按照逆时针 旋转坐标
        public static Vector3 GetPosByAngle2(float x, float y, float z, int r)
        {
            Vector3 pos = new Vector3(x, y, z);
            if (r == 1)// 90
            {
                pos.x = -z;
                pos.z = x;
            }
            else if (r == 2)// 180
            {
                pos.x = -x;
                pos.z = -z;
            }
            else if (r == 3)// 270
            {
                pos.x = z;
                pos.z = -x;
            }
            return pos;
        }

        public static Vector3 GetTileOffset(int tileIdx)
        {
            Vector3 offset = Vector3.zero;
            int tile_x = tileIdx % _allianceTileLineNum;
            int tile_y = tileIdx / _allianceTileLineNum;
            offset.x = (tile_x + 0.5f) * WorldEntry.m_iTileSize;
            offset.z = (tile_y + 0.5f) * WorldEntry.m_iTileSize;
            return offset;
        }

        public static TileElement GetTileElementByAngle(TileElement element,chunckInfoDta data)
        {
            if (data.rotation <= 0) return element;
            if (element.resID == (int)WorldEntry.ConstResId.cloud) return element;
            TileElement newElement = new TileElement(element);
            // 旋转位置
            newElement.position = GetPosByAngle(element.position.x, element.position.y, element.position.z, data.rotation);
            // 临时处理 树不旋转
            string path = MapPrefabMapRunTime[element.resID];
            string[] paths = path.Split("/");
            string name = paths[paths.Length - 1];
            if (!name.Contains("tree") )
            {
                newElement.rotation.y += data.rotation * 90;
            }
            return newElement;
        }

        // ===================================== 性能分级 =====================================
        private static int mapChunckLevel = 2;// 地图块元素性能等级 2 初级 全加载 1 中级 部分加载 0 高级 全部装饰物不加载 这个等级和地图块元素分级等级相反
        // 设置 地图块元素显示等级
        public static void SetMapChunckLevel(int level)
        {
            mapChunckLevel = level;
        }

        // 获取 地图块元素显示等级
        public static int GetMapChunckLevel()
        {
            return mapChunckLevel;
        }

        private static int mapDebugChunckShowId = 0;// <= 0 无效值 > 0有效值
        private static bool bMapDebug = false;// 开启地图Debug模式
        private static Dictionary<int,int> mapChunckEntityNum = new Dictionary<int, int>() { 
        };
        private static Dictionary<int, int> mapChunckEntityType = new Dictionary<int, int>() { // 地图块元素资源配置id 对应类型 每次debug时要检查一下
            [2] = 1,[3] = 1,[32] = 1,
            [26] = 2,[27] = 2,[28] = 2,
            [37] = 3,[42] = 3,[45] = 3,[48] = 3,
            [22] = 4,[23] = 4,[24] = 4,[25] = 4,[29] = 4,[30] = 4,[31] = 4,
        };
        /// <summary>
        /// 设置 开启地图Debug模式
        /// </summary>
        /// <param name="value"></param>
        public static void SetMapDebug(bool value)
        {
            bMapDebug = value;
        }

        public static bool GetMapDebug()
        {
            return bMapDebug;
        }
        /// <summary>
        /// 设置 地图块元素显示数量
        /// </summary>
        /// <param name="type">资源类型 1 树 2 小车 3 阻挡 4 围栏等装饰物</param>
        /// <param name="num">数量 -1 不限制</param>
        public static void SetMapDebugChunckEntityNum(int type,int num)
        {
            mapChunckEntityNum[type] = num;
        }

        /// <summary>
        /// 获得 地图块元素显示数量
        /// </summary>
        /// <param name="type">资源类型 1 树 2 小车 3 阻挡 4 围栏等装饰物</param>
        /// <returns>数量 -1 不限制</returns>
        public static int GetMapDebugChunckEntityNum(int type)
        {
            int num = -1;
            if (mapChunckEntityNum.ContainsKey(type))
            {
                num = mapChunckEntityNum[type];
            }
            return num;
        }

        /// <summary>
        /// 通过资源id获取 资源类型
        /// </summary>
        /// <param name="resId"> 资源id </param>
        /// <returns></returns>
        public static int GetMapChunckEntityTypeByResId(int resId)
        {
            int type = 0;
            if (mapChunckEntityType.ContainsKey(resId))
            {
                type = mapChunckEntityType[resId];
            }
            return type;
        }

        /// <summary>
        /// 设置 地图块显示id
        /// </summary>
        /// <param name="chunckId"> mapPrefabMap.txt中地图块对应id </param>
        public static void SetMapDebugChunckShowId(int chunckId)
        {
            mapDebugChunckShowId = chunckId;
        }

        // ===================================== 地图lod 和 旋转 =====================================

        public class chunckInfoDta
        {
            public int roadType;
            public int chunckType;
            public int rotation;
            public int lod;

            public chunckInfoDta()
            {
            }
            public chunckInfoDta(chunckInfoDta data)
            {
                this.roadType = data.roadType;
                this.chunckType = data.chunckType;
                this.rotation = data.rotation;
                this.lod = data.lod;
            }
        }

        //sandtable_道路类型_地表分布_旋转_lod层级
        //道路类型：1~n
        //地表分布：1~n
        //地表分布：0 -0° 1 -90° 2 -180° 3 -270°
        //lod层级：lod1 -对应沙盘lod1 ~lod2地表 lod3 -对应沙盘lod3 ~lod4地表
        //sandtable_2_3_0_lod1 对应配置id 2 * 1000000 + 3 * 10000 +  0*10 + 1*1
        // 解析地图块id 
        public static chunckInfoDta GetChunckInfoById(int chunckId)
        {
            chunckInfoDta data = new chunckInfoDta();
            data.roadType = chunckId / 1000000;
            data.chunckType = (chunckId % 1000000) / 10000;
            data.rotation = (chunckId % 10000) / 10;
            data.lod = chunckId % 10;
            return data;
        }

        public static int GetChunckIdByInfo(chunckInfoDta data)
        {
            int id = 0;
            id = data.roadType * 1000000 + data.chunckType * 10000 + data.rotation * 10 + data.lod * 1;
            return id;
        }

        // ===================================== 地图迷雾 =====================================
        public static void LoadMapFogData(LuaFunction callBack)
        {
            LoadingUtils.RecodeTimeStart("LoadMapFogData");
            if (m_resLoader == null) m_resLoader = ResLoader.Alloc();
            string mapFogDataPath = "Assets/ResourcesAssets/World/mapdata/mapFogData.asset";
            if (m_resLoader == null)
            {
                m_resLoader = ResLoader.Alloc();
            }
            m_resLoader.Add2Load(mapFogDataPath, (bool success, string assetName, object asset) =>
            {
                if (success)
                {
                    Debug.Log("[沙盘加载] =================== UpdateMaFogpData 开始 =================== ");
                    UpdateMapFogData(asset);
                    if (callBack != null)
                    {
                        callBack?.Action();
                    }
                    LoadingUtils.RecodeTimeEnd("LoadMapFogData");
                }
            });
           m_resLoader.Load();
           
        }

        public static void UpdateMapFogData(object asset)
        {
            // 直接使用加载数据
            m_mapFogData = asset as WorldMapFogData;
            m_mapFogTiles = new Dictionary<int, List<Vector2Int>>(m_mapFogData.mapFogRunDtas.Count);
            m_mapFogIdxToId = new Dictionary<int, int>(m_mapFogData.mapFogRunDtas.Count);
            // 解析数据
            for (int i = 0; i < m_mapFogData.mapFogRunDtas.Count; i++)
            {
                MapFogRunDta fog = m_mapFogData.mapFogRunDtas[i];
                // 解析idx - id 映射
                m_mapFogIdxToId[fog.indexFog] = fog.exploreId;
                // 解析该位置所属id
                Vector2Int fogIdx = new Vector2Int(fog.indexFog_x, fog.indexFog_y);
                if (!m_mapFogTiles.ContainsKey(fog.exploreId))
                {
                    m_mapFogTiles[fog.exploreId] = new List<Vector2Int>(9);
                }
                m_mapFogTiles[fog.exploreId].Add(fogIdx);
            }
        }

        public static int GetFogIdByIndex(int idx)
        {
            int id = 0;
            if (m_mapFogIdxToId != null && m_mapFogIdxToId.ContainsKey(idx))
            {
                id = m_mapFogIdxToId[idx];
            }
            return id;
        }

        public static List<Vector2Int> GetFogTilesById(int id)
        {
            List<Vector2Int> tiles = null;
            if (m_mapFogTiles != null && m_mapFogTiles.ContainsKey(id))
            {
                tiles = m_mapFogTiles[id];
            }
            return tiles;
        }

        public static WorldMapFogData GetFogData()
        {
            return m_mapFogData;
        }

        // ===================================== 街区点道路 =====================================
        static Dictionary<int, Dictionary<int, TileAlliancePointRoad>> _alliancePointRoads = new Dictionary<int, Dictionary<int, TileAlliancePointRoad>>(); // <chunckId,<posIdx,TileAlliancePointRoad>>
        static Dictionary<int, Dictionary<int, TileAlliancePointCross>> _alliancePointCross = new Dictionary<int, Dictionary<int, TileAlliancePointCross>>();// <chunckId,<posIdx + 10 * angleIdx,TileAlliancePointCross>>

        public static void InitChunckData(int chunckId, List<TileAlliancePointRoad> alliancePointRoads, List<TileAlliancePointCross> alliancePointCross)
        {
            if (!_alliancePointRoads.ContainsKey(chunckId) && alliancePointRoads != null)
            {
                Dictionary<int, TileAlliancePointRoad> roads = new Dictionary<int, TileAlliancePointRoad>();
                for (int i = 0; i < alliancePointRoads.Count; i++)
                {
                    TileAlliancePointRoad road = alliancePointRoads[i];
                    roads[road.localIdx] = road;
                }
                _alliancePointRoads[chunckId] = roads;
            }
            if (!_alliancePointCross.ContainsKey(chunckId) && alliancePointCross != null)
            {
                Dictionary<int, TileAlliancePointCross> crosses = new Dictionary<int, TileAlliancePointCross>();
                for (int i = 0; i < alliancePointCross.Count; i++)
                {
                    TileAlliancePointCross cross = alliancePointCross[i];
                    crosses[cross.localIdx * 10 + cross.angleIdx ] = cross; // 键值通过localIdx * 10 + angleIdx 拼接
                }
                _alliancePointCross[chunckId] = crosses;
            }
        }

        public static TileAlliancePointRoad GetRoad(int chunckId, int localIdx)
        {
            TileAlliancePointRoad road = null;
            if (_alliancePointRoads.ContainsKey(chunckId))
            {
                road = _alliancePointRoads[chunckId][localIdx];

            }
            return road;
        }

        public static TileAlliancePointCross GetCross(int chunckId, int localIdx, int angleIdx)
        {
            TileAlliancePointCross cross = null;
            if (_alliancePointCross.ContainsKey(chunckId))
            {
                cross = _alliancePointCross[chunckId][localIdx * 10 + angleIdx];
            }
            return cross;
        }

        // ===================================== 出生点装饰物 =====================================

        static Dictionary<int, Dictionary<int, List<TilePointAdornData>>> chunck_level_n = new Dictionary<int, Dictionary<int, List<TilePointAdornData>>>();
        static Dictionary<int, Dictionary<int, List<TilePointAdornData>>> chunck_level_2 = new Dictionary<int, Dictionary<int, List<TilePointAdornData>>>();
        static Dictionary<int, Dictionary<int, List<TilePointAdornData>>> chunck_level_1 = new Dictionary<int, Dictionary<int, List<TilePointAdornData>>>();
        static Dictionary<int, Dictionary<int, List<TilePointAdornData>>> chunck_level_null = new Dictionary<int, Dictionary<int, List<TilePointAdornData>>>();
        static Dictionary<int, Dictionary<int, List<TilePointAdornData>>> chunck_level_road = new Dictionary<int, Dictionary<int, List<TilePointAdornData>>>();

        static Dictionary<int, List<TilePointAdornData>> chunck_level_null2 = new Dictionary<int, List<TilePointAdornData>>();
        static Dictionary<int, List<TilePointAdornData>> chunck_level_road2 = new Dictionary<int, List<TilePointAdornData>>();

        static Dictionary<int, List<TilePointAdornData>> chunck_level_n2 = new Dictionary<int, List<TilePointAdornData>>();
        static Dictionary<int, List<TilePointAdornData>> chunck_level_22 = new Dictionary<int, List<TilePointAdornData>>();
        static Dictionary<int, List<TilePointAdornData>> chunck_level_12 = new Dictionary<int, List<TilePointAdornData>>();


        static Dictionary<int, Dictionary<int, Vector3>> chunck_cfgIdx = new Dictionary<int, Dictionary<int, Vector3>>();

        public static void InitChunckAdornData(int chunckId, MapChunckData data)
        {
            if (data != null && data.pointAdornDatas != null)
            {
                for (int i = 0; i < data.pointAdornDatas.Count; i++)
                {
                    TilePointAdornData adornData = data.pointAdornDatas[i];
                    // [1,4] 代表方向 顺时针 [5,8] 代表边 顺时针 上右下左 10 代表三级装饰物 9 代表衔接道路 11 代表空置装饰物 -1无效值 0无 但是表示两出生点相连
                    int pointNum = adornData.pointIdxs.Count;
                    if (adornData.type >= 1 && adornData.type <= 4)
                    {
                        if (pointNum == 1)
                        {
                            AddAdornLevel_1(chunckId, adornData.pointIdxs[0], adornData);
                            AddAdornLevel_12(chunckId, adornData);
                        }
                    
                    }
                    else if ((adornData.type >= 5 && adornData.type <= 8) || adornData.type == 0)
                    {
                        if (pointNum == 2)
                        {
                            AddAdornLevel_2(chunckId, adornData.pointIdxs[0], adornData);
                            AddAdornLevel_2(chunckId, adornData.pointIdxs[1], adornData);
                            AddAdornLevel_22(chunckId, adornData);
                        }
                    }
                    else if (adornData.type == 10)
                    {
                        for (int ii = 0; ii < adornData.pointIdxs.Count; ii++)
                        {
                            AddAdornLevel_n(chunckId, adornData.pointIdxs[ii], adornData);
                            AddAdornLevel_n2(chunckId, adornData);
                        }
                    }
                    else if(adornData.type == 9)
                    {
                        if (pointNum == 1)
                        {
                            AddAdornLevel_road(chunckId, adornData.pointIdxs[0], adornData);
                            AddAdornLevel_road2(chunckId, adornData);
                        }
                    }
                    else if (adornData.type == 11)
                    {
                        if (pointNum == 1) {
                            AddAdornLevel_null(chunckId, adornData.pointIdxs[0], adornData);
                            AddAdornLevel_null2(chunckId, adornData);
                        }
                    }
                }
            }

            //for (int i = 0; i < data.mapLayers.Count; i++)
            //{
            //    var layer = data.mapLayers[i];
            //    if (layer.layerID == WorldEntry.MAP_POINT_ID)
            //    {
            //        AddChunckCfgIdx(chunckId, layer);
            //        break;
            //    }
            //}
        }

        public static void AddAdornLevel_n(int chunckId, int pointCfgIdx, TilePointAdornData data)
        {
            if (!chunck_level_n.ContainsKey(chunckId)) chunck_level_n[chunckId] = new Dictionary<int, List<TilePointAdornData>>();
            if (!chunck_level_n[chunckId].ContainsKey(pointCfgIdx)) chunck_level_n[chunckId][pointCfgIdx] = new List<TilePointAdornData>();
            chunck_level_n[chunckId][pointCfgIdx].Add(data);
        }
        public static void AddAdornLevel_2(int chunckId, int pointCfgIdx, TilePointAdornData data)
        {
            if (!chunck_level_2.ContainsKey(chunckId)) chunck_level_2[chunckId] = new Dictionary<int, List<TilePointAdornData>>();
            if (!chunck_level_2[chunckId].ContainsKey(pointCfgIdx)) chunck_level_2[chunckId][pointCfgIdx] = new List<TilePointAdornData>();
            chunck_level_2[chunckId][pointCfgIdx].Add(data);
        }
        public static void AddAdornLevel_1(int chunckId, int pointCfgIdx, TilePointAdornData data)
        {
            if (!chunck_level_1.ContainsKey(chunckId)) chunck_level_1[chunckId] = new Dictionary<int, List<TilePointAdornData>>();
            if (!chunck_level_1[chunckId].ContainsKey(pointCfgIdx)) chunck_level_1[chunckId][pointCfgIdx] = new List<TilePointAdornData>();
            chunck_level_1[chunckId][pointCfgIdx].Add(data);
        }
        public static void AddAdornLevel_null(int chunckId, int pointCfgIdx, TilePointAdornData data)
        {
            if (!chunck_level_null.ContainsKey(chunckId)) chunck_level_null[chunckId] = new Dictionary<int, List<TilePointAdornData>>();
            if (!chunck_level_null[chunckId].ContainsKey(pointCfgIdx)) chunck_level_null[chunckId][pointCfgIdx] = new List<TilePointAdornData>();
            chunck_level_null[chunckId][pointCfgIdx].Add(data);
        }
        public static void AddAdornLevel_road(int chunckId, int pointCfgIdx, TilePointAdornData data)
        {
            if (!chunck_level_road.ContainsKey(chunckId)) chunck_level_road[chunckId] = new Dictionary<int, List<TilePointAdornData>>();
            if (!chunck_level_road[chunckId].ContainsKey(pointCfgIdx)) chunck_level_road[chunckId][pointCfgIdx] = new List<TilePointAdornData>();
            chunck_level_road[chunckId][pointCfgIdx].Add(data);
        }
        public static void AddAdornLevel_null2(int chunckId, TilePointAdornData data)
        {
            if (!chunck_level_null2.ContainsKey(chunckId)) chunck_level_null2[chunckId] = new List<TilePointAdornData>();
            chunck_level_null2[chunckId].Add(data);
        }
        public static void AddAdornLevel_n2(int chunckId, TilePointAdornData data)
        {
            if (!chunck_level_n2.ContainsKey(chunckId)) chunck_level_n2[chunckId] = new List<TilePointAdornData>();
            chunck_level_n2[chunckId].Add(data);
        }
        public static void AddAdornLevel_22(int chunckId, TilePointAdornData data)
        {
            if (!chunck_level_22.ContainsKey(chunckId)) chunck_level_22[chunckId] = new List<TilePointAdornData>();
            chunck_level_22[chunckId].Add(data);
        }
        public static void AddAdornLevel_12(int chunckId, TilePointAdornData data)
        {
            if (!chunck_level_12.ContainsKey(chunckId)) chunck_level_12[chunckId] = new List<TilePointAdornData>();
            chunck_level_12[chunckId].Add(data);
        }
        public static void AddAdornLevel_road2(int chunckId, TilePointAdornData data)
        {
            if (!chunck_level_road2.ContainsKey(chunckId)) chunck_level_road2[chunckId] = new List<TilePointAdornData>();
            chunck_level_road2[chunckId].Add(data);
        }

        public static void AddChunckCfgIdx(int chunckId, MapChunckLayer layer)
        {
            //int halfSize = layer.layerSize / 2;
            //if (!chunck_cfgIdx.ContainsKey(chunckId))
            //{
            //    chunck_cfgIdx[chunckId] = new Dictionary<int, Vector3>();
            //    MapChunckElementData datas = layer.elementDatas[0];
            //    Debug.Log(string.Format("================================ 加载{0}点数据 ================================", chunckId));
            //    for (int i = 0; i < datas.elementDatas.Count; i++)
            //    {
            //        TileElement element = datas.elementDatas[i];
            //        Vector3 pos = element.position;
            //        int x = (int)(pos.x + halfSize);
            //        int z = (int)(pos.z + halfSize);
            //        int cfgIdx = x + z * layer.layerSize;
            //        Debug.Log(string.Format("================================ pos: {0} cfgIdx: {1} ================================", cfgIdx, pos.ToString()));
            //        chunck_cfgIdx[chunckId][cfgIdx] = pos;
            //    }
            //}
        }

        //public enum E_AdornType
        //{
        //    E_Level_1 = 1,
        //    E_Level_2 = 2,
        //    E_Level_n = 3,
        //    E_Road = 4,// 衔接道路
        //    E_Null = 5,// 空置装饰物
        //}

        public static List<TilePointAdornData> GetAdornDatas(int chunckId, int pointCfgIdx, int type)
        {
            List<TilePointAdornData> datas = null;
            Dictionary<int, Dictionary<int, List<TilePointAdornData>>> mic = null;
            if (type == 5)
            {
                mic = chunck_level_null;
            }
            else if(type == 4)
            {
                mic = chunck_level_road;
            }
            else if (type == 3)
            {
                mic = chunck_level_n;
            }
            else if (type == 2)
            {
                mic = chunck_level_2;
            }
            else if (type == 1)
            {
                mic = chunck_level_1;
            }
            if (mic != null && mic.ContainsKey(chunckId) && mic[chunckId].ContainsKey(pointCfgIdx))
            {
                datas = mic[chunckId][pointCfgIdx];
            }
            return datas;
        }

        public static List<TilePointAdornData> GetChunckAdornDatas(int chunckId, int type)
        {
            List<TilePointAdornData> datas = null;
            Dictionary<int, List<TilePointAdornData>> mic = null;
            if (type == 5)
            {
                mic = chunck_level_null2;
            }
            else if (type == 4)
            {
                mic = chunck_level_road2;
            }
            else if (type == 3)
            {
                mic = chunck_level_n2;
            }
            else if (type == 2)
            {
                mic = chunck_level_22;
            }
            else if (type == 1)
            {
                mic = chunck_level_12;
            }
            if (mic != null && mic.ContainsKey(chunckId))
            {
                datas = mic[chunckId];
            }
            return datas;
        }

        public static bool GetAlliancePointIdxIsDelete(int mapIdx)
        {
            bool bDelete = false;
            if (MapDeleteAlliancePoint != null)
            {
                MapDeleteAlliancePoint.TryGetValue(mapIdx, out bDelete);
            }
            return bDelete;
        }

        public static Vector3 GetPosByPosIdx(int posIdx)
        {
            Vector3 pos = Vector3.zero;
            if (m_mapPointPos != null)
            {
                m_mapPointPos.TryGetValue(posIdx, out MapPointInfo mapPointInfo);
                if (mapPointInfo != null)
                {
                    pos = mapPointInfo.pos;
                }
                else
                {
                    UnityEngine.Debug.LogWarningFormat("获取GetPosByPosIdx 报错  posIdx = ={0}",posIdx);
                }
                
            }
           
            return pos;
        }

        public static Vector3 GetPosByPosIdx(int tileIdx, int posIdx)
        {
            Vector3 pos = GlobalValue.INVISIBLE_POSITION;
            // 获取对应tileIdx地图块数据 + 偏移
            Vector3 tileOffset = GetTileOffset(tileIdx);
            int chunckId1 = GetTileResId(1, tileIdx, out int tileSize); // 此时的chunckId可能是旋转过的
            int cfgIdx = math.abs(posIdx % 1000);
            if (MapPointPosRunTime.TryGetValue(chunckId1, out Dictionary<int, Vector3> posMap))
            {
                if (posMap.TryGetValue(cfgIdx, out Vector3 localPos))
                {
                    pos = tileOffset + localPos;
                }
            }
            else
            {
                chunckInfoDta data = GetChunckInfoById(chunckId1);
                int rotation = data.rotation;
                data.rotation = 0;
                int chunckId0 = GetChunckIdByInfo(data);
                if (MapChunckDataRunTime != null && MapChunckDataRunTime.TryGetValue(chunckId0, out MapChunckData chunckData))
                {
                    Dictionary<int, Vector3> posMap1 = new Dictionary<int, Vector3>(0);
                    // 将chunckData中出生点坐标模拟旋转填充到MapPointPosRunTime中
                    for (int i = 0; i < chunckData.mapLayers.Count; i++)
                    {
                        MapChunckLayer layer = chunckData.mapLayers[i];
                        int halfSize = layer.layerSize / 2;
                        if (layer.layerID == WorldEntry.MAP_POINT_ID && layer.elementDatas.Count > 0)
                        {
                            MapChunckElementData elementDatas = layer.elementDatas[0]; // 出生点没有粒度 直接取数组第一个
                            posMap1 = new Dictionary<int, Vector3>(elementDatas.elementDatas.Count);
                            for (int ii = 0; ii < elementDatas.elementDatas.Count; ii++)
                            {
                                TileElement elementData = elementDatas.elementDatas[ii];
                                Vector3 localPos0 = elementData.position;
                                Vector3 localPos = GetPosByAngle(localPos0.x, localPos0.y, localPos0.z, rotation);
                                int x = (int)(localPos.x + halfSize);
                                int z = (int)(localPos.z + halfSize);
                                int cfgIdx1 = x + z * layer.layerSize;
                                posMap1[cfgIdx1] = localPos;
                                if (cfgIdx1 == cfgIdx)
                                {
                                    pos = tileOffset + localPos;
                                }
                            }
                        }
                    }
                    MapPointPosRunTime[chunckId1] = posMap1;
                }
            }
            return pos;
        }

        public static Vector3 GetPosByCfgIdx(int chunckId, int cfgIdx,out bool find)
        {
            Vector3 pos = Vector3.zero;
            find = true;
            //if (chunck_cfgIdx.TryGetValue(chunckId, out Dictionary<int, Vector3> dic))
            //{
            //    find = dic.TryGetValue(cfgIdx, out pos);
            //}
            //else
            //{
            //    find = false;
            //}
            return pos;
        }


        // ===================================== 海外副本 =====================================

        // 将世界坐标转化为地图数据坐标 给负数坐标的装饰地图用
        // 注: 因为可能各层级的粒度不一样 所以要传入坐标系的粒度
        public static int GetOverSeaTileIdx(int tile_x, int tile_y, int tileSize)
        {
            int tileIdx = 0;
            int offset = (WorldEntry.m_mapDataOffset) / tileSize; // 这里因为地图数据存在-60的区域 所有中心点有所偏移
            tile_x += offset;
            tile_y += offset;
            int lineNum = WorldEntry.m_mapDataSize / tileSize;
            tileIdx = tile_x + 1 + tile_y * lineNum; // 避免tile_x 为0 造成结果*m_mapWorldDataMaxIdx也为0
            return tileIdx * m_mapWorldDataMaxIdx; // 因为陆地最大值为 40x40 - 1
        }

        public static bool CheckTileInWorld(int tile_x, int tile_y, int tileSize)
        {
            bool inWorld = true;
            int tileMax = WorldEntry.m_mapSize / tileSize;
            inWorld = tile_x >= 0 && tile_x < tileMax && tile_y >= 0 && tile_y < tileMax;
            return inWorld;
        }

        // 获得lod下tileIndex的海外地块数据 注tileIndex粒度为30
        public static OverSeaChunck GetOverSeaChunckInfo(int lod,int tileIndex)
        {
            if (overSeaChunckIdMap.TryGetValue(lod, out Dictionary<int, OverSeaChunck> overSeaChunckMap))
            {
                if (overSeaChunckMap.TryGetValue(tileIndex, out OverSeaChunck chunckInfo))
                {
                    return chunckInfo;
                }
            }
            return null;
        }

        public static int2 GetOverSeaWorldPosByIdx(int idx,int tileSize)
        {
            idx /= m_mapWorldDataMaxIdx;
            idx = idx - 1;
            int lineNum = WorldEntry.m_mapDataSize / tileSize;
            int tile_x = idx % lineNum;
            int tile_y = idx / lineNum;

            int offset = (WorldEntry.m_mapDataOffset) / tileSize;
            tile_x -= offset;
            tile_y -= offset;
            return new int2(tile_x, tile_y);
        }

        // 检查世界坐标系x,y 在陆地!!!
        public static bool CheckPosInWorld(int x, int y)
        {
            return x >= 0 && y >= 0 && x <= WorldEntry.m_mapLandSize && y <= WorldEntry.m_mapLandSize;
        }

        public static string CheckPointInOverSea(float x,float y)
        {
            string res = "";
            Vector2 point = new Vector2(x, y);
            foreach (var key in overSeaShapes.Keys)
            {
                if (rayCasting(point, overSeaShapes[key]) > 0)
                {
                    res = key;
                    break;
                }
            }
            return res;
        }

        /// <summary>
        /// 射线法，判断一个坐标点是否在多边形区域内
        /// </summary>
        /// <param name="p"></param>
        /// <param name="poly"></param>
        /// <returns>1 在某个顶点上 2 在某段线段上 3 在多边形内 -1 在多边形外</returns>
        public static int rayCasting(Vector2 p, List<Vector2> poly)
        {
            var px = p.x;
            var py = p.y;
            var flag = false;

            int l = poly.Count;
            int j = l - 1;

            for (var i = 0; i < l; i++)
            {
                var sx = poly[i].x;
                var sy = poly[i].y;
                var tx = poly[j].x;
                var ty = poly[j].y;

                // 点与多边形顶点重合
                if ((sx == px && sy == py) || (tx == px && ty == py))
                {
                    return 1;
                }

                // 判断线段两端点是否在射线两侧
                if ((sy < py && ty >= py) || (sy >= py && ty < py))
                {
                    // 线段上与射线 Y 坐标相同的点的 X 坐标
                    var x = sx + (py - sy) * (tx - sx) / (ty - sy);

                    // 点在多边形的边上
                    if (x == px)
                    {
                        return 2;
                    }

                    // 射线穿过多边形的边界
                    if (x > px)
                    {
                        flag = !flag;
                    }
                }
                j = i;
            }

            // 射线穿过多边形边界的次数为奇数时点在多边形内
            return flag ? 3 : -1;
        }
    }
}
